//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Web.UI;
using CommunityServer.Components;
using System.Collections;
using System.Text;

namespace CommunityServer.Controls
{
	/// <summary>
	/// Summary description for TagCloud.
	/// </summary>
	public class BaseTagCloud : Control
	{
		protected CSContext csContext = CSContext.Current;
		protected ArrayList ranges = null;
		protected ArrayList tags = null;

		#region Properties

		int _minimumPostsPerTag = 1;
		public int MinimumPostsPerTag
		{
			get
			{
				return _minimumPostsPerTag;
			}
			set
			{
				_minimumPostsPerTag = value;
			}
		}

		int _maximumNumberOfTags = 100;
		public int MaximumNumberOfTags
		{
			get
			{
				return _maximumNumberOfTags;
			}
			set
			{
				_maximumNumberOfTags = value;
			}
		}

		bool _showTagCounts = false;
		public bool ShowTagCounts
		{
			get
			{
				return _showTagCounts;
			}
			set
			{
				_showTagCounts = value;
			}
		}

		string[] _filterTags = null;
		public virtual string[] FilterTags
		{
			get
			{
				if (IgnoreFilterTags)
					return null;
				else if (_filterTags == null)
					return csContext.Tags;
				else
					return _filterTags;
			}
			set
			{
				_filterTags = value;
			}
		}

		private bool _ignoreFilterTags = false;
		public bool IgnoreFilterTags
		{
			get
			{
				return _ignoreFilterTags;
			}
			set
			{
				_ignoreFilterTags = value;
			}
		}

		protected virtual ArrayList Tags
		{
			get
			{
				if (tags == null)
				{
					if (this.FilterTags != null)
						tags = CommunityServer.Components.Tags.GetTags(this.FilterTags);
					else
						tags = CommunityServer.Components.Tags.GetTags();
				}

				return tags;
			}
		}

		bool _showNoTagsMessage = true;
		public bool ShowNoTagsMessage
		{
			get
			{
				return _showNoTagsMessage;
			}
			set
			{
				_showNoTagsMessage = value;
			}
		}

		string _tagCloudCssClasses = String.Empty;
		public string TagCloudCSSClasses
		{
			get
			{
				return _tagCloudCssClasses;
			}
			set
			{
				_tagCloudCssClasses = value;
				if (!Globals.IsNullorEmpty(_tagCloudCssClasses))
				{
					_tagCloudCssClassesArray = _tagCloudCssClasses.Split(',');
					for (int i = 0; i < _tagCloudCssClassesArray.Length; i++)
					{
						_tagCloudCssClassesArray[i] = _tagCloudCssClassesArray[i].Trim();
					}
				}
				else
					_tagCloudCssClassesArray = new string[0];
			}
		}

		string[] _tagCloudCssClassesArray = new string[0];
		public string[] TagCloudCssClassesArray
		{
			get
			{
				return _tagCloudCssClassesArray;
			}
		}

		string _cssClass = String.Empty;
		public string CssClass
		{
			get
			{
				return _cssClass;
			}
			set
			{
				_cssClass = value;
			}
		}

		#endregion

		#region Event Handlers

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad (e);

			DataBind();
		}

		#endregion

		#region Data Binding

		public override void DataBind()
		{
			base.DataBind ();

			if (Tags.Count > MaximumNumberOfTags)
			{
				tags.Sort(new TotalCountSorter());
				tags = tags.GetRange(tags.Count - MaximumNumberOfTags, MaximumNumberOfTags);
				tags.Sort(new NameSorter());
			}

			ArrayList values = new ArrayList();
			Tag tag;
			for (int i = 0; i < Tags.Count; i++)
			{
				tag = (Tag) Tags[i];

				if (tag.TotalCount >= this.MinimumPostsPerTag)
				{
					values.Add(tag.TotalCount);
				}
				else
				{
					Tags.RemoveAt(i);
					i--;
				}
			}

			values.Sort();
			if (values.Count > 0 && TagCloudCssClassesArray.Length > 0)
			{
				ranges = new ArrayList();
				double itemsPerGroup = ((double) values.Count - 1) / ((double) TagCloudCssClassesArray.Length);
				
				for (int i = 0; i < TagCloudCssClassesArray.Length; i++)
				{
					ranges.Add(new RangeGroup(
						(int) values[(int) (itemsPerGroup * i)], 
						(int) values[(int) (itemsPerGroup * (i + 1))], 
						TagCloudCssClassesArray[i])
						);
				}
			}
		}

		protected override void Render(HtmlTextWriter writer)
		{
			if (Tags != null && Tags.Count > 0)
			{
				writer.Write("<ul class=\"");
				writer.Write(this.CssClass);
				writer.WriteLine("\">");

				foreach (Tag tag in Tags)
				{
					writer.Write("<li class=\"");
					writer.Write(GetTagCloudCssClass(tag.TotalCount));
					writer.Write("\"><a href=\"");
					writer.Write(GetTagUrl(tag.Name));
					writer.Write("\" rel=\"tag\">");
					writer.Write(tag.Name);

					if (this.ShowTagCounts)
					{
						writer.Write(" (");
						writer.Write(tag.TotalCount.ToString());
						writer.Write(")");
					}
				
					writer.WriteLine("</a></li>");
				}

				writer.WriteLine("</ul>");
			}
			else if (this.ShowNoTagsMessage)
			{
				writer.Write("<div class=\"");
				writer.Write(this.CssClass);
				writer.WriteLine("\">");

				if (this.FilterTags != null && this.FilterTags.Length > 0)
                    writer.Write(ResourceManager.GetString("TagCloud_NoSubTagsDefined"));
				else
					writer.Write(ResourceManager.GetString("TagCloud_NoTagsDefined"));

				writer.WriteLine("</div>");
			}
		}

		#endregion

		#region Helper Methods and Classes

		protected virtual string GetTagUrl(string tagName)
		{
			if (this.FilterTags == null)
				return SiteUrls.Instance().TagsBrowser(new String[] {tagName});
			else
			{
				ArrayList linkTags = new ArrayList(this.FilterTags);
				linkTags.Add(tagName);
				return SiteUrls.Instance().TagsBrowser((string[]) linkTags.ToArray(typeof(string)));
			}
		}

		public string GetTagCloudCssClass(int totalCount)
		{
			if (ranges == null || ranges.Count == 0)
				return "";
			
			RangeGroup range;
			for (int i = 0; i < ranges.Count; i++)
			{
				range = (RangeGroup) ranges[i];
				if (totalCount >= range.From && totalCount <= range.To)
					return range.CssClass;
			}

			return ((RangeGroup) ranges[ranges.Count - 1]).CssClass;
		}

		class RangeGroup
		{
			public int From;
			public int To;
			public string CssClass;

			public RangeGroup(int from, int to, string cssClass)
			{
				From = from;
				To = to;
				CssClass = cssClass;
			}
		}

		class TotalCountSorter : IComparer
		{
			#region IComparer Members

			public int Compare(object x, object y)
			{
				Tag tag1 = (Tag) x;
				Tag tag2 = (Tag) y;

				return tag1.TotalCount.CompareTo(tag2.TotalCount);
			}

			#endregion

		}

		class NameSorter : IComparer
		{
			#region IComparer Members

			public int Compare(object x, object y)
			{
				Tag tag1 = (Tag) x;
				Tag tag2 = (Tag) y;

				return tag1.Name.CompareTo(tag2.Name);
			}

			#endregion

		}


		#endregion
	}

	public class TagCloud : CommunityServer.Controls.BaseTagCloud
	{
		#region Properties

		public string FilterByTags
		{
			get
			{
				return String.Join(",", FilterTags);
			}
			set
			{
				ArrayList tags = new ArrayList();
				foreach (string tag in value.Split(','))
				{
					if (!Globals.IsNullorEmpty(tag.Trim()))
						tags.Add(tag.Trim());
				}
				FilterTags = (string[]) tags.ToArray(typeof(string));
			}
		}

		ApplicationType _applicationType = ApplicationType.Unknown;
		public ApplicationType ApplicationType
		{
			get
			{
				return _applicationType;
			}
			set
			{
				_applicationType = value;
			}
		}

		public string Sections
		{
			get
			{
				StringBuilder sections = new StringBuilder();
				if (SectionsArray != null)
				{
					foreach (int id in SectionsArray)
					{
						if (sections.Length > 0)
							sections.Append(",");

						sections.Append(id.ToString());
					}
				}

				return sections.ToString();
			}
			set
			{
				ArrayList sections = new ArrayList();
				foreach (string section in value.Split(','))
				{
					if (!Globals.IsNullorEmpty(section.Trim()))
						sections.Add(int.Parse(section));
				}
				SectionsArray = (int[]) sections.ToArray(typeof(int));
			}
		}

		int[] _sectionsArray = null;
		public int[] SectionsArray
		{
			get
			{
				if (_sectionsArray == null && csContext.SectionID > -1)
					_sectionsArray = new int[] { csContext.SectionID };

				return _sectionsArray;
			}
			set
			{
				_sectionsArray = value;
			}
		}

		public string Groups
		{
			get
			{
				StringBuilder groups = new StringBuilder();
				if (GroupsArray != null)
				{
					foreach (int id in GroupsArray)
					{
						if (groups.Length > 0)
							groups.Append(",");

						groups.Append(id.ToString());
					}
				}

				return groups.ToString();
			}
			set
			{
				ArrayList groups = new ArrayList();
				foreach (string group in value.Split(','))
				{
					if (!Globals.IsNullorEmpty(group.Trim()))
						groups.Add(int.Parse(group));
				}
				GroupsArray = (int[]) groups.ToArray(typeof(int));
			}
		}

		int[] _groupsArray = null;
		public int[] GroupsArray
		{
			get
			{
				if (_groupsArray == null && csContext.GroupID > -1)
					_groupsArray = new int[] { csContext.GroupID };

				return _groupsArray;
			}
			set
			{
				_groupsArray = value;
			}
		}

		protected override ArrayList Tags
		{
			get
			{
				if (tags == null)
				{
					if (SectionsArray != null && SectionsArray.Length > 0)
					{
						if (this.FilterTags != null)
							tags = CommunityServer.Components.Tags.GetTagsBySections(this.SectionsArray, this.FilterTags);
						else
							tags = CommunityServer.Components.Tags.GetTagsBySections(this.SectionsArray);
					}
					else if (GroupsArray != null && GroupsArray.Length > 0)
					{
						if (this.FilterTags != null)
							tags = CommunityServer.Components.Tags.GetTagsByGroups(this.GroupsArray, this.FilterTags);
						else
							tags = CommunityServer.Components.Tags.GetTagsByGroups(this.GroupsArray);
					}
					else if (this.ApplicationType != ApplicationType.Unknown)
					{
						if (this.FilterTags != null)
							tags = CommunityServer.Components.Tags.GetTags(this.ApplicationType, this.FilterTags);
						else
							tags = CommunityServer.Components.Tags.GetTags(this.ApplicationType);
					}
					else
					{
						if (this.FilterTags != null)
							tags = CommunityServer.Components.Tags.GetTags(this.FilterTags);
						else
							tags = CommunityServer.Components.Tags.GetTags();
					}
				}

				return tags;
			}
		}

		#endregion
	}
}
